home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 4
/
Aminet 4 - November 1994.iso
/
aminet
/
comm
/
net
/
spakparnet_0_5.lha
/
par
/
par.s
< prev
next >
Wrap
Text File
|
1992-11-09
|
18KB
|
559 lines
include ":stone/dazsys/macros.i"
include ":stone/dazsys/xrefs.i"
;
; Parrallel port driver (c) Spak, SST Scientific Endeavours
; currently implemented for the parallel port
; contact: c9107253@xenon.newcastle.edu.au (1994)
;
; Cable is the same as that for parnet
;
; I didn't use the parnet.device because I couldn't find it at the time
;
; this is a pretty pathetic method of pumping data thru the parallel port
; since it is so proc'r intensive & I think that the parallel port limits the
; speed at which data is pumped anyway
;
; assume that all lines are pulled high (if 2 outputs drive the same line
; then the resulting line state will be an active-low 'OR')
;
;
; Note that there is a bit of a patch in the acquiring of the port for sending
; (SetupSend) and the interrupt "on" stuff was moved into the send.c module
**************************** PARNET CABLE COMPATIBLE *****************************
; CABLE: Connect D7-D0,SEL,POUT, and BUSY across,
; Connect ACK to SEL locally:
; Connect GND lines indicated
;
; (2-9) D7-D0 ------------ D7-D0
; (12) POUT ------------ POUT
; (11) BUSY ------------ BUSY PARALLEL PORT
; (13) SEL --+------+-- SEL
; (10) ACK -/ \- ACK
; (18-22) GND ------------ GND
;
; WARNING: you cannot connect RI on the serial port to your
; modem because it interferes with the parallel
; port's SEL line in this configuration.
xdef _SendData ;d0/a0/a1
xdef _ReceiveData ;d0/a0/a1
xdef _BackSendData ;d0/a0/a1
xdef _BackReceiveData ;d0/a0/a1
xdef _RelinquishPort ;none
xdef _SetupSend ;d0/a1 : d0
xdef _SetupReceive ;a1 : d0
xdef _CIAIntRoutine ;to be called in the interrupt
xdef _ChkSum ;a0/d1 : d0
OPT L+
; DATA LINE LOCATIONS (8)
inputaddress = $bfe101 ;parallel port
outputaddress = $bfe101 ;same port
datadirection = $bfe301 ;direction control (0=input, 1=output) as per CIA
; HANDSHAKING CONTROL LINES
syncaddress = $bfd000 ;control bits as per CIA (set or read these)
syncdirection = $bfd200 ;direction of sync lines as per CIA (ie LOW bits for input, HIGH bits for output)
validbit = 1 ;Data on bus is valid (POUT)
ackbit = 0 ;Read data from bus (BUSY)
selbit = 2 ;used to trigger interrupts
; defines of errors
PAR_OK = 0
PAR_ERROR_TIMEOUT = 1
PAR_ERROR_BUSY = 2 ;actually means "timeout on busy"
; CIA interrupt number (using the ciab.resource)
CIAINTB = 4
CIAINTF = (1<<CIAINTB)
AbleICR = -$12
SetICR = -$18
**************************************************************************
ICR_OFF MACRO ;A6 must already have the CIA base
**************************************************************************
; THE PROPPER WAY, WHERE a6 = cia.resource_base
move.l #CIAINTF,d0
jsr AbleICR(a6) ;don't interrupt us
; move.b #CIAINTF,$bfed01 ; THE NAUGHTY WAY
ENDM
**************************************************************************
ICR_ON MACRO ;A6 must already have the CIA base
**************************************************************************
; THE PROPPER METHOD
move.l #(1<<7)+CIAINTF,d0
jsr AbleICR(a6) ;interrupts back on
; move.b #(1<<7)+CIAINTF,$bfed01 ;naughty method
ENDM
**************************************************************************
; MACROS
**************************************************************************
; Wait on a bit from a byte to become 0 or 1, with time out
; if "abort" becomes 1 then the routine branches to abort_label
; \1 \2 \3 \4 \5
; WAITBIT state,bitnumber,address ,abort_address, abort_label
WAITBIT MACRO
__wbklfj_loop_\@:
btst.b \2,\3
IFC '\1','0'
beq.s __djdjjd_ok\@
ELSEIF
bne.s __djdjjd_ok\@
ENDC
tst.b \4
bne \5
bra.s __wbklfj_loop_\@
__djdjjd_ok\@:
ENDM
WAITVALIDHIGH MACRO
WAITBIT 1,#validbit,\1,\2,\3
ENDM
WAITVALIDLOW MACRO
WAITBIT 0,#validbit,\1,\2,\3
ENDM
WAITACKHIGH MACRO
WAITBIT 1,#ackbit,\1,\2,\3
ENDM
WAITACKLOW MACRO
WAITBIT 0,#ackbit,\1,\2,\3
ENDM
SETVALIDHIGH MACRO
bset.b #validbit,\1
ENDM
SETVALIDLOW MACRO
bclr.b #validbit,\1
ENDM
SETACKHIGH MACRO
bset.b #ackbit,\1
ENDM
SETACKLOW MACRO
bclr.b #ackbit,\1
ENDM
SETSELHIGH MACRO
bset.b #selbit,\1
ENDM
SETSELLOW MACRO
bclr.b #selbit,\1
ENDM
WAITSELHIGH MACRO
WAITBIT 1,#selbit,\1,\2,\3
ENDM
WAITSELLOW MACRO
WAITBIT 0,#selbit,\1,\2,\3
ENDM
; HANDSHAKING DONE IN SOFTWARE HERE! (SLOW!!!)
**************************************************************************
; Input: a0 memory buffer to send/receive
; a1 abort flag (when = 0, abort!)
; a4 input/output port address
; a2 control address (with directions already set)
; d0 number of words (ie bytes/2) to get
;
; d2 read data only - temp (should be cleared to begin with
; d1 read data only - updated checksum (should be cleared to begin with)
; d3 valid bit number (input-read, output-write)
; d4 ack bit number (output-read, input-write)
; Valid/Acknowledge bits should be high if sending/receiving for the first time
; Note: these start on waiting/setting acknowledge LOW and end on waiting/setting
; a HIGH, which means the ports can be swapped between input and output with
; no effect (since hi-z drifts high)
**************************************************************************
; READ DATA LOOP
**************************************************************************
rd_mainloop
WAITBIT 0,d3,(a2),(a1),_rd_done ;WAIT VALID LOW
move.b (a4),d2 ;read it
bclr.b d4,(a2) ;SET ACK LOW
add.w d2,d1 ;chk sum
move.b d2,(a0)+ ;put it in memory
WAITBIT 1,d3,(a2),(a1),_rd_done ;WAIT VALID HIGH
move.b (a4),d2 ;read it
bset.b d4,(a2) ;SET ACK HIGH
add.w d2,d1 ;chk sum
move.b d2,(a0)+ ;put it in memory
_ReadData
dbf.w d0,rd_mainloop
addq.w #1,d0 ;fix -1 to 0
_rd_done:
rts
**************************************************************************
; WRITE DATA LOOP
**************************************************************************
wd_mainloop:
move.b (a0)+,(a4) ;write it
bclr.b d3,(a2) ;SET VALID LOW
WAITBIT 0,d4,(a2),(a1),_wd_done ;WAIT ACK LOW
move.b (a0)+,(a4) ;write it
bset.b d3,(a2) ;SET VALID HIGH
WAITBIT 1,d4,(a2),(a1),_wd_done ;WAIT ACK LOW
_WriteData
dbf.w d0,wd_mainloop
addq.w #1,d0 ;fix -1 to 0
_wd_done:
rts
; have to do the handshake in pairs... so we read one byte and
; handshake for the second
**************************************************************************
_Read1Byte:
**************************************************************************
WAITBIT 0,d3,(a2),(a1),_r1b_done ;WAIT VALID LOW
move.b (a4),d2 ;read it
bclr.b d4,(a2) ;SET ACK LOW
add.w d2,d1 ;chk sum
move.b d2,(a0)+ ;put it in memory
WAITBIT 1,d3,(a2),(a1),_r1b_done ;WAIT VALID HIGH
bset.b d4,(a2) ;SET ACK HIGH
subq.w #1,d0 ;read 1 (which counts as 2)
_r1b_done:
rts
; We could get away with just writing out an extra byte but with this
; we will never go outside our given buffer
**************************************************************************
_Write1Byte:
**************************************************************************
move.b (a0)+,(a4) ;write it
bclr.b d3,(a2) ;SET VALID LOW
WAITBIT 0,d4,(a2),(a1),_w1b_done ;WAIT ACK LOW
bset.b d3,(a2) ;SET VALID HIGH
WAITBIT 1,d4,(a2),(a1),_w1b_done ;WAIT ACK LOW
subq.w #1,d0
_w1b_done:
rts
**************************************************************************
_ReceiveData:
**************************************************************************
;input: d0.w = bytes to get (max 32000)
; a0 = dest address
; a1 = abort flag address (aborts if flag goes to 0)
; a2 = check sum address (word)
; a0 is updated
; d0 is returned with the number of WORDS NOT SENT
; SetupReceive should be called prior to this routine
**************************************************************************
movem.l d1-d7/a1-a6,-(sp)
move.l a2,a6 ;a6 <== check sum address
moveq #0,d1 ;check sum
lea syncaddress,a2 ;control reg
lea inputaddress,a4 ;DATA reg
moveq #0,d2 ;temporary (0)
move.b d2,datadirection ;ALL 8 INPUT
moveq #validbit,d3
moveq #ackbit,d4
lsr.w #1,d0 ;BYTES -> WORDS
if cs,do,<addq.w #1,d0>,<bsr _Read1Byte>
bsr _ReadData
move.w d1,(a6) ;checksum return
movem.l (sp)+,d1-d7/a1-a6
rts
**************************************************************************
_BackSendData:
**************************************************************************
; this is the same as the send data except the valid/ack lines are
; reversed in roles (use this for instantly swapping between receiving
; and sending in the same packet)
; also the data has to be EVEN in length
;
;Send Data (Call SetupSend first)
;input: d0.w = number of bytes (MUST BE EVEN, NO CHECKING)
; a0 = location to send
; a1 = abort flag address (aborts if flag goes to 0)
; a0 is updated, d0 is returned with the number of words NOT sent
; SETUP RECEIVE SHOULD BE CALLED PRIOR TO THIS
**************************************************************************
movem.l d1-d7/a1-a6,-(sp)
lea syncaddress,a2 ;parallel control
lea outputaddress,a4 ;parallel port out
move.b #$ff,datadirection ;all 8 lines output
moveq #validbit,d4 ;SWAPPED!
moveq #ackbit,d3
lsr.w #1,d0 ;BYTES -> WORDS
bsr _WriteData
movem.l (sp)+,d1-d7/a1-a6
rts
**************************************************************************
_SendData:
**************************************************************************
;Send Data (Call SetupSend first)
;input: d0.w = number of bytes
; a0 = location to send
; a1 = abort flag address (aborts if flag goes to 0)
; a0 is updated, d0 is returned with the number of words NOT sent
; SetupSend should be called prior to calling this
**************************************************************************
movem.l d1-d7/a1-a6,-(sp)
lea syncaddress,a2 ;parallel control
lea outputaddress,a4 ;parallel port out
move.b #$ff,datadirection ;all 8 lines output
moveq #validbit,d3
moveq #ackbit,d4
lsr.w #1,d0 ;BYTES -> WORDS
if cs,do,<addq.w #1,d0>,<bsr _Write1Byte>
bsr _WriteData
movem.l (sp)+,d1-d7/a1-a6
rts
**************************************************************************
_BackReceiveData:
**************************************************************************
;input: d0.w = bytes to get (max 32000) (MUST BE EVEN FOR THIS!)
; a0 = dest address
; a1 = abort flag address (aborts if flag goes to 0)
; a2 = check sum address (word)
; a0 is updated
; d0 is returned with the number of WORDS NOT SENT
; SetupSend should be called prior to this routine
**************************************************************************
movem.l d1-d7/a1-a6,-(sp)
move.l a2,a6 ;a6 <== check sum address
moveq #0,d1 ;check sum
lea syncaddress,a2 ;control reg
lea inputaddress,a4 ;DATA reg
moveq #0,d2 ;temporary
move.b d2,datadirection ;We want to read 8 lines
moveq #validbit,d4 ;SWAPPED
moveq #ackbit,d3
lsr.w #1,d0 ;BYTES -> WORDS
bsr _ReadData
move.w d1,(a6) ;checksum
movem.l (sp)+,d1-d7/a1-a6
rts
**************************************************************************
_RelinquishPort:
**************************************************************************
; simply makes all lines "input", relinquishing any control over the bus
**************************************************************************
movem.l d1-d7/a1-a6,-(sp)
lea syncaddress,a2 ;parallel control
lea syncdirection,a3 ;parallel control
lea outputaddress,a4 ;parallel port out
** SET ALL TO INPUT (HI-Z)
move.b #0,datadirection ;all 8 lines input
SETVALIDLOW (a3) ;hi-z input
SETACKLOW (a3) ;hi-z input
SETSELLOW (a3) ;hi-z input
** SET ALL LINES HIGH (ie INACTIVE) JUST IN CASE..
SETSELHIGH (a2)
SETACKHIGH (a2)
SETVALIDHIGH (a2)
move.b #$ff,(a4)
; ICR_ON ;(a6) should be already on!
movem.l (sp)+,d1-d7/a1-a6
rts
**************************************************************************
_SetupSend:
**************************************************************************
;input: d0 = machine address to contact
; a1 = address of abort flag
; a6 = cia.resource base (so we can play with the interrupts)
; call this when you want to start communications with another machine
; return (d0) 0 if we got the line ok, 1 if acquisition failed,
; 2 if machine not responding
**************************************************************************
movem.l d1-d7/a1-a6,-(sp)
move.l a1,a5 ;abort (affected by ICR control)
move.b d0,d7 ;machine ID
lea syncaddress,a2 ;parallel sync in/out
lea syncdirection,a3 ;parallel control
lea outputaddress,a4 ;parallel port out
** TRY AND ACQUIRE THE LINE BY CHECKING FOR SEL HIGH
SETVALIDLOW (a3) ;everything is an input
SETACKLOW (a3)
SETSELLOW (a3)
; note that when nobody drives the line SEL *SHOULD* be high!
moveq #PAR_ERROR_BUSY,d0 ;
WAITSELHIGH (a2),(a5),_sus_done ;acquire! (or bomb out)
** CIA can't interrupt us (else we trigger ourselves)
ICR_OFF ;(a6)
** SEND OUT A NEGATIVE TRANSITION ON SEL (WHICH IS CONNECTED TO AN ACK)
SETSELHIGH (a2) ;set / (order is important!)
SETVALIDLOW (a2) ;set valid \ (for handshake)
SETSELHIGH (a3) ;SELECT IS AN OUTPUT
SETVALIDHIGH (a3) ;"VALID" is an output
move.b #$ff,datadirection ;all 8 lines output
move.b d7,(a4) ;put out dest machine
** CAUSE AN INTERRUPT ON THE DEST MACHINE
SETSELLOW (a2) ;SELECT negative edge
** WAIT FOR A LITTLE HANDSHAKE FROM ANOTHER MACHINE
moveq #PAR_ERROR_TIMEOUT,d0
WAITACKLOW (a2),(a5),_sus_intson ;wait ack \
SETVALIDHIGH (a2) ;set valid /
WAITACKHIGH (a2),(a5),_sus_intson ;wait ack /
** WE DON'T WANT INTERRUPT CODE STARTING...
** this refuses to work properly here... moving it to send.c before relinquishport
; move.l #CIAINTF,d0 ;Clear that interrupt
; jsr SetICR(a6) ;put this out of the way
; ICR_ON ;(a6) but turnem on
moveq #PAR_OK,d0 ;everything - OK!
_sus_intson:
_sus_done:
movem.l (sp)+,d1-d7/a1-a6
rts
**************************************************************************
_SetupReceive:
**************************************************************************
;input: a1 is the abort flag address as usual
;return d0 = 0 if got the handshake, d0 = 1 if we timed out
**************************************************************************
movem.l d1-d7/a1-a6,-(sp)
lea syncaddress,a2 ;parallel control
lea syncdirection,a3 ;parallel control
lea outputaddress,a4 ;parallel port out
moveq #PAR_ERROR_TIMEOUT,d0
SETVALIDLOW (a3) ;"VALID" is an INPUT
SETACKHIGH (a3) ;"ACK" is an OUTPUT
WAITVALIDLOW (a2),(a1),_sur_done ;WAIT valid \
SETACKLOW (a2) ;set ack \
WAITVALIDHIGH (a2),(a1),_sur_done ;WAIT valid /
SETACKHIGH (a2) ;set ack /
moveq #PAR_OK,d0
_sur_done:
movem.l (sp)+,d1-d7/a1-a6
rts
**************************************************************************
_CIAIntRoutine:
**************************************************************************
; Please see the c-code part for the interrupt setup
; data_segment (is_Data) a1
; according to the ROM-kernal manual, d0/d1/d0/a1/a5 need not be saved
;
; Assume that the input port is already set up to take input data
; No handshaking is done here since that needs a timer to be set up
; after which setupreceive should be called for the first handshake
;
; count on the ciaa.resource to handle ALL of the interrupt hardware
; including the reseting of the CIA interrupt bits
;
; is_Data should point to
rsset 0
cir_sigmask rs.l 1 ;ORDER IS IMPORTANT!
cir_sigtask rs.l 1
cir_machine rs.b 1 ;if (inputaddress) is this then signal
cir_abort rs.b 1 ;abort flag (set to 1)
cir_pad rs.b 2
cir_ciares rs.l 1 ;cia resource
**************************************************************************
movem.l a6,-(sp)
move.l a1,a5 ;use a5 as the base
; move.w #$f00,$dff180
move.b #-1,cir_abort(a5) ;<-- this stuffs up
** CHECK (inputaddress) AGAINST OUR MACHINE
move.b inputaddress,d0
if.b d0,ne,cir_machine(a5),cir_thatsall ;is it for our machine?
move.b #-2,cir_abort(a5) ;ABORT, in case we are
;still doing something else
** SIGNAL OUR TASK
movem.l cir_sigmask(a5),d0/a1 ;get mask & task!
exec Signal ;a1/d0 : ??
cir_thatsall:
moveq #0,d0
movem.l (sp)+,a6
rts
**************************************************************************
_ChkSum:
**************************************************************************
; "FAST" check summer with unrolled loop
;input a0 buffer (updated)
; d1.w length (trashed)
;output d0 checksum
**************************************************************************
movem.l d2/d3,-(sp)
move.w d1,d2 ;length
lsr.w #4,d1 ;counter
and.w #15,d2 ;leftover
moveq #0,d0 ;sum
moveq #0,d3 ;temp
*** DO the bulk (should really do an offset into this..)
bra.s _csy_skipa
_csy_loopa:
REPT 16 ;unroll this
move.b (a0)+,d3
add.w d3,d0
ENDR
_csy_skipa:
dbf.w d1,_csy_loopa
*** Do the remaining few
bra.s _csy_skipb
_csy_loopb:
move.b (a0)+,d3
add.w d3,d0
_csy_skipb:
dbf.w d2,_csy_loopb
movem.l (sp)+,d2/d3
rts